-
-
Notifications
You must be signed in to change notification settings - Fork 200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add macro for manually registering properties #400
Conversation
API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-400 |
92a3c94
to
2cef439
Compare
Couldn't we do this with something like this (we'd need to add a // Struct containing some shared data not exposed to Godot
struct Foo {
data: Whatever
}
#[derive(GodotClass)]
struct Bar {
foo: Foo,
#[var(type = i32, get = get_data)]
data: (),
}
... impl RefCountedVirtual ...
#[godot_api]
impl Bar {
#[func]
fn get_data(&self) -> i32 {
self.foo.data.some_func()
}
} |
That's a good point. I didn't consider that a field with a unit type could be used. I'm still in favor of the
The following constraints would need to be followed for unit types:
The following question would need to be answered:
#[var(type = Vector2, get = get_my_int)]
my_int: i32 Finally, purely subjectively for my use case:
Real WIP example from my project: #[derive(Debug, GodotClass)]
#[class(base = Node3D)]
#[property(name = head_bone, type = GodotString, get = get_head_bone, set = set_head_bone)]
#[property(
name = additional_movement_bones,
type = Array<i32>, get = get_additional_movement_bones,
set = set_additional_movement_bones
)] // Fixed in latest squashed commit
#[property(name = blink_threshold, type = f32, get = get_blink_threshold, set = set_blink_threshold)]
pub struct VrmPuppet {
puppet3d: model::puppet::Puppet3d,
vrm_puppet: model::puppet::VrmPuppet,
... omitted for brevity ...
}
... getters/setters impl ... |
I dont think we need to add anything other than supporting
I mean if it's a field in godot it usually makes sense to also have it be a field in rust. Otherwise you can just manually write a getter/setter for use in both rust and godot.
understandable :p
Pretty sure this is already the case.
Will also already be the case if we add support for
Probably for consistency
This is already possible.
You dont have to use a unit type, you can use a field of any type you want.
Are you here basically exposing fields internal to |
This would simplify things a lot.
Would it need multiple struct fields that use the same getters/setters? If so, my PR removes the need for multiple redundant fields.
My point was more along the lines of "I don't want redundant fields in my struct". I'm composing Godot structs out of smaller data structs. To explain my example further, I have multiple types: They are not just private fields, it would be clunky to re-expose the inner fields on the outer struct, and registering every data struct with Godot is not a great solution since these structs are just data. |
i mean that sounds like the usecase for |
In my experience, I've found Godot Either way, using |
that's fair, i havent really had the same issue with resource since 4.0 came out and made them so much nicer to use in the editor.
i do agree it should exist, but i dont know if we should add another macro solution to this problem when there exists a workaround and we're already planning on making a builder api that will support this much more nicely. the current implementation also just seems kinda noisy to me. |
I'm open to syntax changes. I just want an escape hatch for what I want to do. Would reusing the #[class(
init,
property = (name = foo, type = i32, get = get_foo, set = set_foo)
)] or this (I'm not sure if #[class(
init,
properties = (
(name = foo, type = i32, get = get_foo, set = set_foo),
(name = bar, ... etc ...)
)
)] or potentially shorter syntax for #[property(blink_threshold: f32, get = get_blink_threshold, set = set_blink_threshold)] |
…ted with a struct field, add tests for #[property(...)] macro, add parse_many to KvParser
2cef439
to
52709eb
Compare
Pushed a new commit that leaves this PR with 2 options for manual property registration:
#[property(name = readonly_int, type = i32, get = get_integer)]
#[class(
properties = [
(name = first_int, type = i32, get = get_integer),
(name = second_int, type = i32, get = get_integer)
]
)] Both examples taken from My preference is still for option 1. because the implementation is cleaner. |
Without reading the whole discussion, why not Class-based attributes seem a bit off for something that's semantically a property (field). It also means that you cannot use Rust's type system and have to resort to proc-macro magic instead. |
I have Godot structs composed out of pure data structs. The pure data structs cannot be bound to Godot as a The Godot structs already have many other implementation-specific fields on them, so I don't want to add extra fields just to bind them to Godot. On the Rust side, they are What I'm essentially looking for is this function from GDNative's ClassBuilder which is a feature that's also present in godot-cpp. I will note that |
But then that would rather be something to make part of the builder API (#4). impl NodeVirtual for MyClass {
fn register_class(builder: &mut ClassBuilder) {
builder.add_property("my_thing")
.getter(get_thing)
.setter(set_thing)
.done();
}
} The API you suggest was the one gdext started with, and we moved towards field-based attributes, as that feels much more natural. And that is currently the API to register properties -- so we should either expand on that one ( Furthermore, I don't think everything provided in a future builder API should additionally be available in a tense proc-macro form. The proc-macro API is for convenience in common cases, but it is a custom, difficult-to-discover DSL with manual validation and compile-time impacts. I'm aware that the builder API is not yet there, but to me, the solution to that problem is not to fill the proc-macro API with builder functionality as a workaround. |
As a general remark, I would recommend to discuss larger changes in an issue first, as mentioned in the Contribution Guidelines. Otherwise it can happen that a lot of effort is spent on something that is not directly mergeable. If you're fine with that risk and like to try out different approaches as a proof-of-concept, that's of course OK 🙂 |
Okay, I will close this PR then. Thanks for considering it. |
To be clear, I'm not against having this as a feature, but I think it could be provided in a slightly different API. In gdnative, we had provided custom properties in two ways:
What is your opinion on those two approaches? |
I'm for option 1, the builder API. Option 2 leads to (in my opinion) redundant struct fields that need to be maintained along with their associated getters/setters + the actual struct field wherever it might be. However, option 1 looks like it will involve a lot of work to implement, whereas option 2 could honestly just use this suggestion from earlier in the thread to achieve the same result. |
Adds a new struct-level macro for manually registering properties.
This is primarily useful for cases like this:
The macro syntax was chosen to (kind of) mirror how godot-cpp handles property registration.
TODO:
Automatically generated getters/settersignore this, brain was confused. This is not possible since manually registered properties are not associated with any struct fieldFor the above todos, I think it should be possible to pass all manually registered properties asFieldVar
s to reduce code duplication as the logic is mostly the same. I will need to investigate further.Refactored to treat manually registered properties as
FieldVar
s. It might be worth it to rename some types since a#[property]
is not actually associated with any struct fields, thus the field name and type need to be explicitly provided.